﻿using System;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using Red.Controls.Diagrams.ViewModels;
using Red.Controls.ViewModels;

namespace Red.Controls.Diagrams.Actions.InteropActions
{
    public class AddDecoratorNodeAction : InteropActionBase
    {
        #region Data

        readonly ActionConnectionData _connectionToRemoveData;
        readonly ActionConnectionData _inputConnectionData;
        readonly ActionConnectionData _outputConnectionData;

        #endregion Data

        #region C-tor

        public AddDecoratorNodeAction( DataItem parentObject, string className, Point position, ConnectionViewModel connectionToRemove, DiagramViewModel viewModel, Func<string, Task> nodeCreator )
        {
            var sourceConnector = connectionToRemove.SourceConnector;
            var destConnector = connectionToRemove.DestConnector;
            _nodeData = new ActionNodeData
            {
                ClassName = className,
                Position = position,
            };
            _connectionToRemoveData = new ActionConnectionData( connectionToRemove );
            _inputConnectionData = new ActionConnectionData
            {
                OutputID = sourceConnector.ID,
                OutputOwnerID = sourceConnector.ParentNode.ID,
                ValueID = Red.GameData.Raw.Utils.FormatGuid( Guid.NewGuid() )
            };
            _outputConnectionData = new ActionConnectionData
            {
                InputID = destConnector.ID,
                InputOwnerID = destConnector.ParentNode.ID,
                ValueID = Red.GameData.Raw.Utils.FormatGuid( Guid.NewGuid() )
            };

            _parentObject = parentObject;
            _viewModel = viewModel;
            _nodeCreator = nodeCreator;
        }

        #endregion C-tor

        #region Public methods

        public async Task ExecuteAsync()
        {
            var operationID = Guid.NewGuid().ToString();

            //Creating Node
            var nodeID = await CreateNodeAsync( _nodeData, _parentObject, operationID );
            var node = _viewModel.FindNode( nodeID );
            RemoveConnectionData( _connectionToRemoveData, operationID );

            //Creating input connection
            var inputConnector = node.InputConnectors.FirstOrDefault();

            _inputConnectionData.InputID = inputConnector.ID;
            _inputConnectionData.InputOwnerID = node.ID;

            CreateConnection( _inputConnectionData, operationID );

            //Creating output connection
            var destConnector = GetInputConnector( _connectionToRemoveData.InputOwnerID, _connectionToRemoveData.InputID );
            var outputConnector = await GetFirstCompatibleOutput( node, destConnector );

            _outputConnectionData.OutputID = outputConnector.ID;
            _outputConnectionData.OutputOwnerID = node.ID;

            CreateConnection( _outputConnectionData, operationID );
        }

        private async Task<ConnectorViewModel> GetFirstCompatibleOutput( NodeViewModel node, ConnectorViewModel destConnector )
        {
            foreach(var connector in node.OutputConnectors )
            {
                var isCompatible = await connector.Property.IsCompatibleWithAsync( destConnector.Property );
                if( isCompatible )
                {
                    return connector;
                }
            }
            return null;
        }

        #endregion Public methods
    }
}
